Zygote进程启动过程分析

zygote进程定义

Init进程是Android系统中用户空间的第一个进程, 它最重要的工作就是创建zygote进程。而在Android系统中,所有应用程序的进程以及系统服务进程SystemServer都是由Zygote进程孕育出来的。所有Zygote的地位非同小可,本文就分析它的启动过程。

Android系统启动后运行的第一个进程是init进程,它的目录在system/core/init/init.cpp 在这里会进行启动属性服务以及解析init.rc文件,init.rc文件是android系统的配置文件,它如下格式所示:

1
2
3
4
5
6
7
8
system/core/rootdir/init.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

每一个service命令都会促使init进程调用fork函数来创建一个新的进程,这里service用于通知init进程创建名zygote的进程,这个zygote进程执行程序的路径为/system/bin/app_process,后面的则是要传给app_process的参数。class main指的是zygote的class name为main。

zygote要执行的程序是system/bin/app_process这样会进入main函数。在main中会执行AppRuntime的start来进一步启动zygote。

frameworks/base/cmds/app_process/app_main.cpp

1
2
3
4
5
6
7
int main(int argc, char* const argv[])
{
……
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server" : "");
……
}

这里的runtime是AppRuntime的实例,AppRuntime是继承自AndroidRuntime,这里的start方法就是在AndroidRuntime里定义的。

//启动android运行时 这包括了启动虚拟机和调用callName所定义的静态main方法 这里时指com.android.internal.os.ZygoteInit

frameworks/base/core/jni/AndroidRuntime.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void AndroidRuntime::start(const char* className, const char* options)
{
……
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {//启动虚拟机
return;
}
onVmCreated(env);

/*
* Register android functions.
*/
if (startReg(env) < 0) {//在虚拟机中注册function
ALOGE("Unable to register all android natives\n");
return;
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);//找到ZygoteInit类
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");//调用静态main方法
}
}

Zygote进程在启动时会创建JavaVM,因此通过fock而创建的应用程序进程和SystemServer进程可以在内部获取一个JavaVM的实例拷贝.在启动zygote时传递进来的类为com.android.internal.os.ZygoteInit,这里通过反射的方式来调用其main方法进一步完成启动初始化的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//在AndroidRuntime的start方法通过反射调用的
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();

registerZygoteSocket();//注册zygote本地Socket服务 监听来自AMS的创建应用进程请求
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();//预加载 一些资源,类等
……
if (argv[1].equals("start-system-server")) {
startSystemServer();//启动SystemServer进程
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}

Log.i(TAG, "Accepting command socket connections");

runSelectLoop();//等待客户端请求

closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();//
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}

在zygote的初始化中,做了以下几件事件:

  1. 通过registerServerSocket创建zygote的socket服务,它是一个LocalSocketServer用来等待AMS请求zygote创建应用进程的请求。
  2. 监听socket服务,等待AMS创建应用程序的请求
  3. 创建SystemServer进程

值得注意的是,无论是创建systemServer进程还是创建应用进程,最终都会通过捕获MethodAndArgsCaller异常来执行参数指定的class的main方法,后面我们分析SystemServer启动及应用进程的启动时就会看到。

这里我们接着看看注册socket服务的代码,它仅仅是创建了LocalServerSocket的本地socket对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static void registerZygoteSocket() {
if (sServerSocket == null) {
int fileDesc;
try {
String env = System.getenv(ANDROID_SOCKET_ENV);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(
ANDROID_SOCKET_ENV + " unset or invalid", ex);
}

try {
sServerSocket = new LocalServerSocket(
createFileDescriptor(fileDesc));
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}

SystemServer进程的创建流程

这里我们重点关注SystemServer的创建流程,继续关注startSystemServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
……
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;

int pid;

try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);//fork 出systemServer进程
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}

/* For child process */
if (pid == 0) {
handleSystemServerProcess(parsedArgs);//在子进程中调用
}

return true;
}

在startSystemServer中仅仅fork出进程后随后进一步在handleSystemServerProcess中进一步对SystemServer进行初始化

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static void handleSystemServerProcess(//进一步处理SystemServer进程的相关工作
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {

closeServerSocket();//关闭从父进程继承来的socket

// set umask to 0077 so new files and directories will default to owner-only permissions.
Libcore.os.umask(S_IRWXG | S_IRWXO);

if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}

if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
null, parsedArgs.remainingArgs);
} else {
/*
* Pass the remaining arguments to SystemServer.
*/
//此时的remainingArgs就是”com.android.server.SystemServer”
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
}

/* should never reach here */
}

这里进一步调用zygoteInit进行初始化工作

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

1
2
3
4
5
6
7
8
9
10
public static final void zygoteInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

redirectLogStreams();

commonInit();
nativeZygoteInit();//zygote本地初始化
applicationInit(targetSdkVersion, argv);////应用层的初始化
}

首先我们来看第一个方法nativeZygoteInit的调用,这个方法时在AndroidRuntime中定义的,具体是

/frameworks/base/core/jni/AndroidRuntime.cpp

1
2
3
4
5
static void
com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}

这里的onZygoteInit是调用其子类AppRuntime的方法,zygote的启动就是通过这个类调用start方法来执行的。

frameworks/base/cmds/app_process/app_main.cpp

1
2
3
4
5
6
7
8
9
virtual void onZygoteInit()
{
// Re-enable tracing now that we're no longer in Zygote.
atrace_set_tracing_enabled(true);

sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}

ProcessState对于binder机制非常重要,这里主要是初始化SystemServer进程的的binder环境,这样在其进程中就可以通过binder同其他进程进行通信了。

下面我们来看看第二个方法applicationInit,这个方法第二个参数包含了调用了类的信息及相关方法的参数,这里就是com.android.server.SystemServer和main方法

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

1
2
3
4
5
6
private static void applicationInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
……
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs);
}

这个方法内部会调用invokeStaticMain方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//这个方法最终会抛出异常MethodAndArgsCaller触发其run方法的调用,具体见ZygoteInit的main方法
private static void invokeStaticMain(String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;

try {
cl = Class.forName(className);//获取类信息 可能是SystemServer或者ActivityThread
} catch (ClassNotFoundException ex) {
}

Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });//获取对应类的main方法
} catch (){}

/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
//抛出异常,通过MethodAndArgsCaller的run方法会去调用main方法
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

MethodAndArgsCaller的定义如下,这里我们重点看看run方法,run方法的实现很简单只是对main方法进行调用。即调用SystemServer的main方法完成SystemServer进程的创建和启动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class MethodAndArgsCaller extends Exception
implements Runnable {
/** method to call */
private final Method mMethod;//调用的方法,这里就是main方法了

/** argument array */
private final String[] mArgs;//参数
……
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
}catch(){…}
}
}

应用进程的创建启动过程

接下来我们分析应用进程创建和启动的过程,这个过程中需要AMS的介入,不过这里我们重点关注应用进程的创建和启动过程,而不需要关注整个流程的太多细节。熟悉AMS的应该知道,当我们点击Launcher启动应用程序后 最终会通过AMS的startProcessLocked方法来为我们的应用程序创建进程,而其内部会进一步调用startProcessLocked来完成,所以我们重点看那startProcessLocked方法。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

1
2
3
4
5
6
7
8
9
10
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
……
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
……
}

这个方法会通过Process的start方法类完成进程的创建,这里我们传递ActivityThread的类名,再我们创建完应用进程后需要就是调用其内部的main方法完成启动过程。下面我们继续去看下进程是如何创建的。

frameworks/base/core/java/android/os/Process.java

1
2
3
4
5
6
7
8
9
10
11
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
} catch (ZygoteStartFailedEx ex) { }
}

Process的start方法很简单,调用startViaZygote,从其名称来看就是通过zygote来创建我们应用进程了。这里的processClass就是我们的ActivityThread类,niceName是进程名称。startViaZygote通过将这一些参数打包到一个ArrayList变量中然后调用zygoteSendArgsAndGetResult,并将打包的参数传递给它。这个方法负责将这些参数通过socket传递给zygote.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx {
openZygoteSocketIfNeeded();
try {
sZygoteWriter.write(Integer.toString(args.size()));
sZygoteWriter.newLine();

int sz = args.size();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
sZygoteWriter.write(arg);
sZygoteWriter.newLine();
}

sZygoteWriter.flush();

// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
result.pid = sZygoteInputStream.readInt();
……
} catch (IOException ex) {
}
}

这个方法首先通过openZygoteSocketIfNeeded方法来打开同zygote通信的socket,并用该socket创建一个BufferedWriter对象sZygoteWrite,随后通过sZygoteWrite将参数发送给zygote,同时创建一个ProcessStartResult对象,用来保存创建的进程信息。

对于zygote端我们知道,当zygote启动后会先注册一个LocalSocketServer服务,然后通过runSelectLoop等待来自AMS创建进程的请求。这里我们就需要看看runSelectLoop方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static void runSelectLoop() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
……
while (true) {
int index;
……
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done;
done = peers.get(index).runOnce();

if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}

runSelectLoop方法主要负责处理客户端的连接请求和客户端的消息处理,当index==0是说明有新的客户端连接,index>0则说明有消息到来,index指定了客户端的连接索引。同时会调用runOnce对消息机型处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//zygote收到客户端AMS的信息进行处理
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
……
try {
args = readArgumentList();//读取客户端发送的消息 得到参数列表
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) { }
……
try {
parsedArgs = new Arguments(args);
……
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);//创建应用进程
} catch () {}
……
try {
if (pid == 0) {
……
//继续处理子进程 这里面最终会抛出ZygoteInit.MethodAndArgsCaller来触发其run方法的调用
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else {………}
} finally { }
}

在这个方法中首先通过readArgumentList方法读取客户端发送的消息,得到参数列表,随后根据参数创建应用进程,随后进一步调用handleChildProc进一步完成子进程的创建。在这个方法中最终会抛出MethodAndArgsCaller异常来触发run方法的调用,就如SystemServer进程那样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {

……
if (parsedArgs.invokeWith != null) {
WrapperInit.execStandalone(parsedArgs.invokeWith,
parsedArgs.classpath, className, mainArgs);
} else {
……
try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);//最终会调用invokeStaticMain方法抛出异常
} catch (RuntimeException ex) {
logAndPrintError(newStderr, "Error starting.", ex);
}
}
}

这个方法会调用invokeStaticMain,这个方法我们在SystemServer启动时候分析过,这里就不再分析了。最终会调用ActivityThread的main方法完成应用进程的启动。

坚持原创技术分享,您的支持将鼓励我继续创作!